﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using KEW.InterFace;

namespace AutoGam
{
    public class UsbCardDevice : ICard
    {
        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_usbopen", SetLastError = true,
       CharSet = CharSet.Auto, ExactSpelling = false,
       CallingConvention = CallingConvention.StdCall)]
        public static extern int rf_usbopen();

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_usbclose", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_usbclose(int icdev);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_beep", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_beep(int icdev, int msec);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_get_status", SetLastError = true,
              CharSet = CharSet.Auto, ExactSpelling = false,
              CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_get_status(int icdev, [MarshalAs(UnmanagedType.LPArray)]byte[] state);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_load_key", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key(int icdev, int mode, int secnr, [MarshalAs(UnmanagedType.LPArray)]byte[] keybuff);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_load_key_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key_hex(int icdev, int mode, int secnr, [MarshalAs(UnmanagedType.LPArray)]byte[] keybuff);


        [DllImport("mwhrf_bj.dll", EntryPoint = "a_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 a_hex([MarshalAs(UnmanagedType.LPArray)]byte[] asc, [MarshalAs(UnmanagedType.LPArray)]byte[] hex, int len);

        [DllImport("mwhrf_bj.dll", EntryPoint = "hex_a", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 hex_a([MarshalAs(UnmanagedType.LPArray)]byte[] hex, [MarshalAs(UnmanagedType.LPArray)]byte[] asc, int len);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_reset", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_reset(int icdev, int msec);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_request", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_request(int icdev, int mode, out UInt16 tagtype);


        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_anticoll", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_anticoll(int icdev, int bcnt, out uint snr);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_select", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_select(int icdev, uint snr, out byte size);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_card", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_card(int icdev, int mode, [MarshalAs(UnmanagedType.LPArray)]byte[] snr);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_authentication", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication(int icdev, int mode, int secnr);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_authentication_2", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication_2(int icdev, int mode, int keynr, int blocknr);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_read", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_read_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read_hex(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_write_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write_hex(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_write", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_halt", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_halt(int icdev);

        [DllImport("mwhrf_bj.dll", EntryPoint = "rf_changeb3", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_changeb3(int icdev, int sector, [MarshalAs(UnmanagedType.LPArray)]byte[] keya, int B0, int B1,
              int B2, int B3, int Bk, [MarshalAs(UnmanagedType.LPArray)]byte[] keyb);


        private static int _device;
        private static short _result = 0;
        private static uint _serial;
        private static byte[] _key = new byte[7];
        private Boolean _enable;
        private String _flag;

        public Boolean Enable { get { return _enable; } }
        public String Flag { get { return _flag; } }

        public UsbCardDevice()
        {
            a_hex(Encoding.ASCII.GetBytes("ffffffffffff"), _key, 12);
            _device = rf_usbopen();
            int st = 0;
            if (_device > 0)
            {
                for (int i = 0; i <= 15; i++)
                {
                    st += rf_load_key(_device, 0, i, _key);
                }
                if (st == 0)
                {
                    _enable = true;
                    Beep();
                }
                else
                {
                    _enable = false;
                }
            }
            else
            {
                _enable = false;
            }
        }

        public Boolean ReSet()
        {
            int st = 0;
            rf_usbclose(_device);
            _device = rf_usbopen();
            if (_device > 0)
            {
                for (int i = 0; i <= 15; i++)
                {
                    st += rf_load_key(_device, 0, i, _key);
                }
                if (st == 0)
                {
                    _enable = true;
                    //Beep();
                }
                else
                {
                    _enable = false;
                }
            }
            else
            {
                _enable = false;
            }
            return Enable;
        }

        public String GetSerial()
        {
            byte[] snr = new byte[5];
            _result = rf_card(_device, 1, snr);
            if (_result == 0)
            {
                byte[] snr1 = new byte[8];
                hex_a(snr, snr1, 4);
                return System.Text.Encoding.Default.GetString(snr1);
            }
            else
            {
                _flag = "GetSerial rf_card 错误" + _result;
                return String.Empty;
            }
        }

        /// <summary>
        /// 读块区
        /// </summary>
        /// <param name="block">块区号</param>
        /// <returns>返回值</returns>
        public String ReadBlock(Block block)
        {
            if (!Enable) return "";
            byte[] output = new byte[32];
            byte[] snr = new byte[5];
            rf_card(_device, 1, snr);
            _result = rf_authentication(_device, 0, (int)((int)block) / 4);
            if (_result == 0)
            {
                _result = rf_read(_device, (int)block, output);
                if (_result == 0)
                {
                    return Encoding.GetEncoding("GBK").GetString(output).Split('\0')[0];
                }
                else
                {
                    _flag = "ReadBlock rf_read 错误" + _result;
                    return String.Empty;
                }
            }
            else
            {
                _flag = "ReadBlock rf_authentication 错误" + _result;
                return String.Empty;
            }
        }

        /// <summary>
        /// 向某一块区中写数据 可写入8个长度的字符
        /// </summary>
        /// <param name="value">信息</param>
        /// <param name="block">块区</param>
        /// <returns>执行结果返回值</returns>
        public Boolean WriteBlock(String value, Block block)
        {
            if (!Enable) return false;
            byte[] snr = new byte[5];
            rf_card(_device, 1, snr);
            _result = rf_authentication(_device, 0, (int)((int)block) / 4);

            if (_result == 0)
            {
                String cut = Left(value, 16);
                byte[] input = Encoding.GetEncoding("GBK").GetBytes(cut);
                _result = rf_write(_device, (int)block, input);
                if (_result == 0)
                {
                    String reload = ReadBlock(block);
                    if (reload == cut)
                    {
                        
                        return true;
                    }
                    else
                    {
                        _flag = "rf_write ReadBlock 校验错误" + _result + ",块区:" + (int)block + "reload:[" + reload + "],原始[" + value + "]";
                        return false;
                    }
                }
                else
                {
                    _flag = "rf_write 错误" + _result + ",块区:" + (int)block;
                    return false;
                }
            }
            else
            {
                _flag = "rf_authentication 错误" + _result + ",块区:" + (int)block;
                return false;
            }
        }

        public void Beep()
        {
            if (!Enable) return;
            rf_beep(_device, 10);
        }

        /// <summary>
        /// 退出
        /// </summary>
        public void Exit()
        {
            if (_device > 0)
            {
                //_result = rf_reset(_device, 10);
                _result = rf_usbclose(_device);
                _device = -1;
            }
        }

        private String Left(String data, int len)
        {
            int curLen = 0;
            int curIdx = 0;
            String retStr = "";
            while (curIdx <= data.Length - 1)
            {
                Byte[] curCharBytes = Encoding.GetEncoding("GBK").GetBytes(data[curIdx].ToString());
                if (curLen + curCharBytes.Length <= len)
                {
                    curLen += curCharBytes.Length;
                    retStr += data[curIdx].ToString();
                    curIdx++;
                }
                else
                {
                    break;
                }

            }

            return retStr;
        }

    }


}
